<template>
  <el-container class="form-builder-container">
    <el-header height="auto" class="builder-header">
      <BuilderToolbar
        :row-count="formDefinition.gridDefinition.rowCount"
        :col-count="formDefinition.gridDefinition.colCount"
        :can-merge="canMergeSelected"
        :can-unmerge="canUnmergeSelected"
        :available-meta-models="availableMetaModels"
        :selected-meta-model-name="formDefinition.dataMetaModel?.name"
        @update:row-count="updateRowCount"
        @update:col-count="updateColCount"
        @merge-selected="mergeSelectedCells"
        @unmerge-selected="unmergeSelectedCell"
        @select-meta-model="selectMetaModel"
        @save-definition="saveFormDefinition"
        @load-definition="loadFormDefinition"
      />
    </el-header>
    <el-container class="builder-body">
      <el-main class="grid-area">
        <GridDesigner
          :grid="formDefinition.gridDefinition"
          :selected-cells="selectedUICells"
          :data-meta-model="formDefinition.dataMetaModel"
          @update:selected-cells="updateSelectedUICells"
          @cell-clicked="handleCellClickedForProps"
          @selection-changed="handleSelectionFinalized"
          @resize-row="handleResizeRow"
          @resize-col="handleResizeCol"
        />
      </el-main>
      <el-aside width="380px" class="properties-area">
        <PropertyEditor
          :active-cell="activeEditingCell"
          :active-row-for-props="activeRowIndexForProps"
          :active-col-for-props="activeColIndexForProps"
          :grid="formDefinition.gridDefinition"
          :data-meta-model="formDefinition.dataMetaModel"
          @update-cell-content="updateCellContent"
          @update-row-prop="updateRowProp"
          @update-col-prop="updateColProp"
        />
      </el-aside>
    </el-container>
  </el-container>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import BuilderToolbar from './BuilderToolbar.vue';
import GridDesigner from './GridDesigner.vue';
import PropertyEditor from './PropertyEditor.vue';

import { FormDefinition } from '@/models/form.model';
import { CellDefinition } from '@/models/cell.model';
import { ContentDefinition } from '@/models/content.model';
import { DataMetaModel } from '@/models/meta-model.model';

const formDefinition = reactive<FormDefinition>(new FormDefinition());

const availableMetaModels = ref<DataMetaModel[]>([
  new DataMetaModel('工单', true, [
    { field: 'code', name: '工单编码', type: 'string' },
    { field: 'title', name: '工单标题', type: 'string' },
    { field: 'status', name: '工单状态', type: 'string' },
    { field: 'priority', name: '优先级', type: 'number' },
    { field: 'assignee', name: '处理人', type: 'user' },
    { field: 'createTime', name: '创建时间', type: 'datetime' },
    { field: 'attachmentUrl', name: '附件URL', type: 'string' },
  ]),
  new DataMetaModel('用户信息', false, [
    { field: 'userId', name: '用户ID', type: 'string' },
    { field: 'username', name: '用户名', type: 'string' },
    { field: 'email', name: '邮箱', type: 'string' },
    { field: 'isActive', name: '是否激活', type: 'boolean' },
    { field: 'avatarUrl', name: '头像URL', type: 'string' },
  ]),
]);

const selectedUICells = ref<CellDefinition[]>([]); // Cells visually selected in GridDesigner
const activeEditingCell = ref<CellDefinition | null>(null); // Primary cell for property editing (content, style)
const activeRowIndexForProps = ref<number | null>(null); // For row-specific properties (e.g., height via slider)
const activeColIndexForProps = ref<number | null>(null); // For col-specific properties (e.g., width via slider)

function updateSelectedUICells(cells: CellDefinition[]): void {
  selectedUICells.value = cells;
}

// Triggered by GridDesigner when a cell is single-clicked (for property editor focus)
function handleCellClickedForProps(cell: CellDefinition | null): void {
  if (cell) {
    activeEditingCell.value = cell;
    activeRowIndexForProps.value = cell.rowIndex;
    activeColIndexForProps.value = cell.colIndex;
    // If only one cell is clicked, ensure it's the only one in selectedUICells for clarity
    if (
      !selectedUICells.value.find((c) => c.key === cell.key) ||
      selectedUICells.value.length > 1
    ) {
      selectedUICells.value = [cell]; // Make it the sole selected UI cell
    }
  } else {
    // Clicked outside cells, or an invalid cell
    activeEditingCell.value = null;
    // Optionally clear row/col props, or keep last active ones
    // activeRowIndexForProps.value = null;
    // activeColIndexForProps.value = null;
  }
}

// Triggered by GridDesigner after a mouse-drag selection is completed
function handleSelectionFinalized(cells: CellDefinition[]): void {
  selectedUICells.value = cells; // Update the visual selection
  if (cells.length === 1) {
    const singleCell = cells[0];
    activeEditingCell.value = singleCell;
    activeRowIndexForProps.value = singleCell.rowIndex;
    activeColIndexForProps.value = singleCell.colIndex;
  } else if (cells.length > 1) {
    // For multi-selection, typically the first cell in the selection becomes active for props
    activeEditingCell.value = cells[0];
    activeRowIndexForProps.value = cells[0].rowIndex;
    activeColIndexForProps.value = cells[0].colIndex;
  } else {
    // No cells selected (e.g., cleared selection)
    activeEditingCell.value = null;
    activeRowIndexForProps.value = null;
    activeColIndexForProps.value = null;
  }
}

function updateRowCount(newCount: number): void {
  formDefinition.gridDefinition.updateRowCount(newCount);
  clearActiveElementsIfOutOfBounds();
}
function updateColCount(newCount: number): void {
  formDefinition.gridDefinition.updateColCount(newCount);
  clearActiveElementsIfOutOfBounds();
}

function clearActiveElementsIfOutOfBounds(): void {
  const { rowCount, colCount } = formDefinition.gridDefinition;
  if (
    activeEditingCell.value &&
    (activeEditingCell.value.rowIndex >= rowCount ||
      activeEditingCell.value.colIndex >= colCount)
  ) {
    activeEditingCell.value = null;
  }
  selectedUICells.value = selectedUICells.value.filter(
    (c) => c.rowIndex < rowCount && c.colIndex < colCount
  );
  if (selectedUICells.value.length === 0 && !activeEditingCell.value) {
    // if selection cleared and active cell was also cleared
    activeRowIndexForProps.value = null;
    activeColIndexForProps.value = null;
  } else if (activeEditingCell.value) {
    // if active cell still valid, keep its row/col props active
    activeRowIndexForProps.value = activeEditingCell.value.rowIndex;
    activeColIndexForProps.value = activeEditingCell.value.colIndex;
  }

  if (
    activeRowIndexForProps.value !== null &&
    activeRowIndexForProps.value >= rowCount
  ) {
    activeRowIndexForProps.value = rowCount > 0 ? rowCount - 1 : null; // Select last valid or null
  }
  if (
    activeColIndexForProps.value !== null &&
    activeColIndexForProps.value >= colCount
  ) {
    activeColIndexForProps.value = colCount > 0 ? colCount - 1 : null;
  }
}

const canMergeSelected = computed(() => {
  if (selectedUICells.value.length <= 1) return false;
  // Advanced check: ensure selected cells form a rectangle and don't cross existing master merges
  let minR = Infinity,
    maxR = -1,
    minC = Infinity,
    maxC = -1;
  let hasMasterMergeConflict = false;
  selectedUICells.value.forEach((cell) => {
    minR = Math.min(minR, cell.rowIndex);
    maxR = Math.max(maxR, cell.rowIndex + cell.rowSpan - 1); // consider existing spans for bounding box
    minC = Math.min(minC, cell.colIndex);
    maxC = Math.max(maxC, cell.colIndex + cell.colSpan - 1);
    if (cell.rowSpan > 1 || cell.colSpan > 1) {
      // Cannot merge if selection includes a master cell of another merge
      // This logic needs to be more robust: if multiple cells selected, and one is a master,
      // merging is complex. For now, a simple check.
    }
    if (cell.isMergedSlave) hasMasterMergeConflict = true; // Cannot start merge from a slave
  });
  if (hasMasterMergeConflict) return false;
  // Check if the bounding box contains any other master cells not part of the current selection
  // This is simplified. A true Excel-like check is more complex.
  return true;
});

const canUnmergeSelected = computed(() => {
  if (activeEditingCell.value) {
    // Unmerge usually acts on the primary active cell
    const cell = activeEditingCell.value;
    if (cell.rowSpan > 1 || cell.colSpan > 1 || cell.isMergedSlave) return true;
  }
  return false;
});

function mergeSelectedCells(): void {
  if (!canMergeSelected.value || selectedUICells.value.length === 0) return;
  let minR = Infinity,
    minC = Infinity,
    maxR = -1,
    maxC = -1;
  selectedUICells.value.forEach((cell) => {
    minR = Math.min(minR, cell.rowIndex);
    minC = Math.min(minC, cell.colIndex);
    // For merge, we use the original cell's top-left, not its spanned area end
    maxR = Math.max(maxR, cell.rowIndex);
    maxC = Math.max(maxC, cell.colIndex);
  });

  if (formDefinition.gridDefinition.mergeCells(minR, minC, maxR, maxC)) {
    ElMessage.success('单元格已合并');
    const masterCell = formDefinition.gridDefinition.getCell(minR, minC);
    if (masterCell) {
      // cell 选择新的 master cell
      selectedUICells.value = [masterCell];
      activeEditingCell.value = masterCell;
      activeRowIndexForProps.value = masterCell.rowIndex;
      activeColIndexForProps.value = masterCell.colIndex;
    }
  } else {
    ElMessage.error(
      '无法合并：选区可能与现有合并冲突、包含从属单元格或不构成有效合并区域。'
    );
  }
}

function unmergeSelectedCell(): void {
  if (!canUnmergeSelected.value || !activeEditingCell.value) return;
  const cellToUnmerge = activeEditingCell.value;

  if (
    formDefinition.gridDefinition.unmergeCells(
      cellToUnmerge.rowIndex,
      cellToUnmerge.colIndex
    )
  ) {
    ElMessage.success('合并已取消');
    const currentCell = formDefinition.gridDefinition.getCell(
      cellToUnmerge.rowIndex,
      cellToUnmerge.colIndex
    );
    if (currentCell) {
      selectedUICells.value = [currentCell];
      activeEditingCell.value = currentCell;
      activeRowIndexForProps.value = currentCell.rowIndex;
      activeColIndexForProps.value = currentCell.colIndex;
    }
  } else {
    ElMessage.info('单元格未合并或无法取消。');
  }
}

function updateCellContent(
  cellDef: CellDefinition,
  newContent: ContentDefinition
): void {
  const targetCell = formDefinition.gridDefinition.getCell(
    cellDef.rowIndex,
    cellDef.colIndex
  );
  if (targetCell) {
    targetCell.content = newContent;
    if (activeEditingCell.value?.key === targetCell.key) {
      // Ensure reactivity for PropertyEditor
      activeEditingCell.value = targetCell;
    }
  }
}
function updateRowProp(payload: {
  rowIndex: number;
  propName: 'height';
  value: number;
}): void {
  if (payload.propName === 'height') {
    formDefinition.gridDefinition.setRowHeight(payload.rowIndex, payload.value);
  }
}
function updateColProp(payload: {
  colIndex: number;
  propName: 'width';
  value: number;
}): void {
  if (payload.propName === 'width') {
    formDefinition.gridDefinition.setColWidth(payload.colIndex, payload.value);
  }
}

function handleResizeRow(payload: { index: number; height: number }): void {
  formDefinition.gridDefinition.setRowHeight(payload.index, payload.height);
  activeRowIndexForProps.value = payload.index; // Update slider if this row is active
}
function handleResizeCol(payload: { index: number; width: number }): void {
  formDefinition.gridDefinition.setColWidth(payload.index, payload.width);
  activeColIndexForProps.value = payload.index; // Update slider
}

function selectMetaModel(name: string | null | undefined): void {
  if (name) {
    formDefinition.dataMetaModel = availableMetaModels.value.find(
      (m) => m.name === name
    );
  } else {
    formDefinition.dataMetaModel = undefined;
  }
  // TODO: Consider prompting user if they want to clear existing cell dataMetaModelField bindings
  // if the new model doesn't contain those fields or if the model is removed.
  // For now, bindings might become orphaned if fields are removed.
}

function saveFormDefinition(): void {
  try {
    console.log('表单定义已保存到LocalStorage (Key: formBuilderDefinition)');
    const json = formDefinition.toJson();
    console.log(json);
    localStorage.setItem('formBuilderDefinition', json);
    ElMessage.success(
      '表单定义已保存到LocalStorage (Key: formBuilderDefinition)'
    );
  } catch (error) {
    console.error('Error saving form definition:', error);
    ElMessage.error('保存失败，详情请查看控制台。');
  }
}

function loadFormDefinition(): void {
  ElMessageBox.prompt(
    '请输入保存在LocalStorage的Key（默认formBuilderDefinition）或直接粘贴JSON定义',
    '加载表单定义',
    {
      confirmButtonText: '加载',
      cancelButtonText: '取消',
      inputValue: 'formBuilderDefinition',
      inputPlaceholder: '输入Key或JSON字符串',
    }
  )
    .then(({ value }: { value: string }) => {
      let jsonToParse = value.trim();
      if (!jsonToParse) {
        ElMessage.error('输入不能为空');
        return;
      }

      if (!jsonToParse.startsWith('{')) {
        const storedJson = localStorage.getItem(jsonToParse); // Assume it's a key
        if (storedJson) {
          jsonToParse = storedJson;
        } else {
          ElMessage.error(`未在LocalStorage中找到Key: ${jsonToParse}`);
          return;
        }
      }

      try {
        const newFormDef = FormDefinition.fromJson(jsonToParse);
        formDefinition.name = newFormDef.name;
        formDefinition.gridDefinition = newFormDef.gridDefinition; // This assignment should trigger reactivity
        formDefinition.dataMetaModel = newFormDef.dataMetaModel;

        activeEditingCell.value = null;
        selectedUICells.value = [];
        activeRowIndexForProps.value = null;
        activeColIndexForProps.value = null;
        ElMessage.success('表单定义已加载');
      } catch (error: unknown) {
        console.error('Error loading form definition:', error);
        ElMessage.error(
          `加载表单定义失败: ${(error as Error).message || '格式错误'}`
        );
      }
    })
    .catch(() => {
      ElMessage.info('取消加载');
    });
}

onMounted(() => {
  // You might want to auto-load if 'formBuilderDefinition' exists in localStorage
  const autoLoad = false; // Set to true to enable
  if (autoLoad) {
    const storedJson = localStorage.getItem('formBuilderDefinition');
    if (storedJson) {
      try {
        const newFormDef = FormDefinition.fromJson(storedJson);
        formDefinition.name = newFormDef.name;
        formDefinition.gridDefinition = newFormDef.gridDefinition;
        formDefinition.dataMetaModel = newFormDef.dataMetaModel;
        ElMessage.info('已自动加载上次保存的定义');
      } catch (e) {
        console.warn('Failed to auto-load stored definition', e);
        localStorage.removeItem('formBuilderDefinition'); // Clear corrupted data
      }
    }
  }
});
</script>

<style lang="scss" scoped>
.form-builder-container {
  height: calc(100vh - 20px);
  min-height: 600px;
  display: flex;
  flex-direction: column;
  border: 1px solid #dcdfe6;
}

.builder-header {
  padding: 10px 15px;
  border-bottom: 1px solid #dcdfe6;
  background-color: #f5f7fa;
  flex-shrink: 0;
}

.builder-body {
  flex-grow: 1;
  display: flex;
  overflow: hidden;
}

.grid-area {
  flex-grow: 1;
  padding: 10px;
  background-color: #fff;
  overflow: auto;
  position: relative;
}

.properties-area {
  flex-shrink: 0;
  border-left: 1px solid #dcdfe6;
  background-color: #fff;
  overflow: hidden;
}
</style>
